package com.sdy.sd;

import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.os.Build;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.RequiresApi;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import java.util.ArrayList;
import java.util.Comparator;

public class SdView extends View implements View.OnClickListener{
    private float mUnitWid = 0f;
    private float mUnitHeight = 0f;
    private final float mPadding = 40;
    public static final String POP_CLEAR_CHAR = "X";
    private static final int FULL_SCREEN_FLAG = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
            View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN;
    private final String TAG = "sdView";
    public SdGame mGame = null;
    PopupWindow mPopWindow = null;
    private int mTouchedRow = -1;
    private int mTouchedCol = -1;

    //for drawing
    Paint mChutePaint = null;
    Paint mLightPaint = null;
    Paint mNumberFixedPaint = null;
    Paint mNumberUsrPaint = null;
    float mNumOffsetX = 0f;
    float mNumOffsetY = 0f;
    Paint mUsrBgPaint = null;
    Paint mAnswerBgPaint = null;
    Paint mCkErrBgPaint = null;
    Paint mTouchedBorderPaint = null;
    Paint mPaintWinMask = null;
    View mRootView = null;

    public SdView(Context context) {super(context);initPaint();}
    public SdView(Context context, AttributeSet attrs) {super(context, attrs);initPaint();}

    public void initPaint() {
        mRootView = getRootView();

        mChutePaint = new Paint();
        mChutePaint.setColor(getResources().getColor(R.color.chute_border));
        mChutePaint.setStrokeWidth(3);

        mLightPaint = new Paint();
        mLightPaint.setColor(getResources().getColor(R.color.grid_border));

        mNumberFixedPaint = new Paint();
        mNumberFixedPaint.setTextAlign(Paint.Align.CENTER);
        mNumberFixedPaint.setColor(getResources().getColor(R.color.unit_txt_fixed));

        mNumberUsrPaint = new Paint();
        mNumberUsrPaint.setTextAlign(Paint.Align.CENTER);
        mNumberUsrPaint.setColor(getResources().getColor(R.color.unit_txt_usr));

        mUsrBgPaint = new Paint();
        mUsrBgPaint.setColor(getResources().getColor(R.color.unit_bg_usr));

        mAnswerBgPaint = new Paint();
        mAnswerBgPaint.setColor(getResources().getColor(R.color.unit_bg_answer));
        mCkErrBgPaint = new Paint();
        mCkErrBgPaint.setColor(getResources().getColor(R.color.unit_bg_check_err));

        mTouchedBorderPaint = new Paint();
        mTouchedBorderPaint.setStyle(Paint.Style.STROKE);
        mTouchedBorderPaint.setColor(getResources().getColor(R.color.unit_border_touched));
        mTouchedBorderPaint.setStrokeWidth(6);

        mPaintWinMask = new Paint();
        mPaintWinMask.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
        mPaintWinMask.setStyle(Paint.Style.FILL);
        mPaintWinMask.setColor(Color.argb(200, 0, 0, 0));
    }
    public SdView mainRegionReset() {
        mTouchedRow = -1;
        mTouchedCol = -1;
        return this;
    }

    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        mUnitWid = (w - 2 * mPadding) / 9f ;
        mUnitHeight = (h - 2 * mPadding) / 9f ;

        mNumberFixedPaint.setTextSize(mUnitHeight * 0.75f);
        mNumberUsrPaint.setTextSize(mUnitHeight * 0.75f);
        mNumOffsetX = mUnitWid / 2f;
        Paint.FontMetrics fm = mNumberFixedPaint.getFontMetrics();
        mNumOffsetY = mUnitHeight / 2f - (fm.ascent + fm.descent) / 2;

        super.onSizeChanged(w, h, oldw, oldh);
    }

    private void subDrawUnit(Canvas canvas, int row, int col) {
        float left = col * mUnitWid + mPadding + 2;
        float top = row * mUnitHeight + mPadding + 2;
        float right = left + mUnitWid - 4;
        float bottom = top + mUnitHeight - 4;

        if(0 != (SdUnit.PROP_CHECK_ERR & mGame.getUnit(row, col).mProp)) {
            canvas.drawRect(left, top, right, bottom, mCkErrBgPaint);

            if((SdHint.ST_HINT_ON == mGame.mHint.mHintSt) && mTouchedRow == row && mTouchedCol == col) {
                canvas.drawRect(left + 2, top + 2, right - 2, bottom - 3, mTouchedBorderPaint);
            }

            canvas.drawText(mGame.getUnitText(row, col), col * mUnitWid + mNumOffsetX + mPadding,row * mUnitHeight + mNumOffsetY + mPadding , mNumberFixedPaint);
            return;
        }

        if(mGame.isForUser(row, col)) {
            canvas.drawRect(left, top, right, bottom, mUsrBgPaint);  //draw user region background
            if((SdHint.ST_HINT_ON == mGame.mHint.mHintSt) && mTouchedRow == row && mTouchedCol == col) {
                canvas.drawRect(left + 2, top + 2, right - 2, bottom - 2, mTouchedBorderPaint);
            }
            canvas.drawText(mGame.getUnitText(row, col), col * mUnitWid + mNumOffsetX + mPadding,row * mUnitHeight + mNumOffsetY + mPadding , mNumberUsrPaint);
            return;
        }
        if(SdUnit.PROP_SEE_ANSWER == mGame.getUnit(row, col).mProp) {
            canvas.drawRect(left, top, right, bottom, mAnswerBgPaint);  //draw user region background
            canvas.drawText(mGame.getUnitText(row, col), col * mUnitWid + mNumOffsetX + mPadding,row * mUnitHeight + mNumOffsetY + mPadding , mNumberFixedPaint);
            return;
        }
        canvas.drawText(mGame.getUnitText(row, col), col * mUnitWid + mNumOffsetX + mPadding,row * mUnitHeight + mNumOffsetY + mPadding , mNumberFixedPaint);
    }

    public void onDraw(Canvas canvas) {
        //canvas.drawRect(0, 0, getWidth(), getHeight(), mBgPaint);

        //9row 9col border line
        for(int i = 0 ; i < 10 ; ++i) {
            Paint curPaint = mLightPaint;
            if(i % 3 == 0) curPaint = mChutePaint;
            canvas.drawLine(mPadding, i * mUnitHeight + mPadding, mUnitWid * 9 + mPadding, i * mUnitHeight + mPadding, curPaint); //row
            canvas.drawLine(i * mUnitWid + mPadding, mPadding, i * mUnitWid + mPadding, mUnitHeight * 9 + mPadding, curPaint); //col
        }

        //draw unit
        for(int row = 0 ; row < 9 ; row ++) {
            for(int col = 0 ; col < 9 ; col ++) {
                subDrawUnit(canvas, row, col);
            }
        }
        if(0 != (mGame.mGameSt & SdGame.GMST_FLAG_WIN_ANI)) {
            //assert (SdGame.GMST_DONE_WIN == (mGame.mGameSt & 0xFF));
            canvas.drawPaint(mPaintWinMask);
        }
        super.onDraw(canvas);
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    public boolean onTouchEvent(MotionEvent event) {
        if( event.getAction() != event.ACTION_DOWN ) {
            return super.onTouchEvent(event);
        }
        if(SdGame.GMST_DONE_WIN == (mGame.mGameSt & 0xFF) || SdGame.GMST_DONE_SEE_ANSWER == mGame.mGameSt) return true;

        mTouchedRow = (int)((event.getY() - mPadding) / mUnitHeight) ;
        mTouchedCol = (int)((event.getX() - mPadding) / mUnitWid);
        if(mTouchedRow < 0 | mTouchedRow > 8 | mTouchedCol < 0 | mTouchedCol > 8) {
            return true;
        }

        //Log.e(TAG, "[" + row + ", " + col + "] was touched.");
        String s = mGame.getUnitText(mTouchedRow, mTouchedCol);

        if(!mGame.canPopup(mTouchedRow, mTouchedCol)) {
            return true;
        }

        showPopupWindow();
        return true;
    }

    private int addPopupItem(LinearLayout pnt, String txt) {
        ViewGroup.LayoutParams vlp = new ViewGroup.LayoutParams((int)mUnitWid - 5 * 2, (int)mUnitHeight); //padding 5px of unit container
        TextView tv = new TextView(getContext());
        tv.setLayoutParams(vlp);
        tv.setText(txt);
        tv.setTextSize(24);
        tv.setTextColor(getResources().getColor(R.color.popup_txt));
        tv.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
        tv.setOnClickListener(this);
        pnt.addView(tv);

        View split = new View(getContext());
        vlp.height = 1;
        split.setLayoutParams(vlp);
        split.setBackgroundColor(getResources().getColor(R.color.popup_boder_split));
        pnt.addView(split);
        return 0;
    }
    @RequiresApi(api = Build.VERSION_CODES.N) // ArrayList.sort
    private void showPopupWindow() {
        View contentView = LayoutInflater.from(getContext()).inflate(R.layout.popuplayout, null);
        assert (contentView instanceof LinearLayout);
        LinearLayout popupLayout = (LinearLayout)contentView;

        int liCnt = 0;
        if(mGame.isSetDone(mTouchedRow, mTouchedCol)) {
            addPopupItem(popupLayout, POP_CLEAR_CHAR);
            ++liCnt;
        }
        ArrayList<Integer> li = mGame.getPopupListItems(mTouchedRow, mTouchedCol);
        li.sort(new Comparator<Integer>() {public int compare(Integer o1, Integer o2) {return (o1 - o2); }});
        for(int i : li) {
            addPopupItem(popupLayout, Integer.toString(i));
        }
        liCnt += li.size();
        assert (liCnt > 0);
        mPopWindow = new PopupWindow(contentView, (int)mUnitWid - 5 * 2, (int)(mUnitHeight * liCnt), true); //padding 5px of unit container
        mPopWindow.setContentView(contentView);
        mPopWindow.setFocusable(false);
        invalidate(); //redraw the selected grid with the thick border, search select_grid_border
        mPopWindow.showAtLocation(mRootView, Gravity.TOP | Gravity.LEFT, (int)(mPadding + mTouchedCol * mUnitWid + 5), (int)(mPadding + mTouchedRow * mUnitHeight + 5));
        mPopWindow.getContentView().setSystemUiVisibility(FULL_SCREEN_FLAG);
        mPopWindow.setFocusable(true);
        mPopWindow.update();
    }

    public void onClick(View v) {
        assert(v instanceof TextView);
        TextView tv = (TextView)v;
        int remain = mGame.onPopupItemSelected(mTouchedRow, mTouchedCol, tv.getText().toString(), getContext());
        invalidate();
        mPopWindow.dismiss();
        assert (remain >= 0);
        if(remain != 0) return;
        if(0 == mGame.checkWin()) {
            LocalBroadcastManager.getInstance(getContext()).sendBroadcast(new Intent("notifyWin"));
            return;
        }
        Toast.makeText(getContext(),"勘違いあるらしいね! ", Toast.LENGTH_SHORT).show();
        return;
    }
}
